package com.thaiopensource.datatype.xsd.regex.java.gen;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

public class CategoriesGen
{
  static public void main (final String [] args) throws IOException
  {
    if (args.length != 3)
    {
      System.err.println ("usage: " + CategoriesGen.class.getName () + " className srcDir UnicodeData.txt");
      System.exit (2);
    }
    final BufferedReader r = new BufferedReader (new InputStreamReader (new FileInputStream (args[2])));
    final CategoriesGen g = new CategoriesGen ();
    g.load (r);
    String className = args[0];
    String srcDir = args[1];
    final int lastDot = className.lastIndexOf ('.');
    String pkg;
    if (lastDot < 0)
      pkg = null;
    else
    {
      pkg = className.substring (0, lastDot);
      className = className.substring (lastDot + 1);
      srcDir = srcDir + File.separator + pkg.replace ('.', File.separatorChar);
    }
    final String srcFile = srcDir + File.separator + className + ".java";
    final OutputStream stm = new FileOutputStream (srcFile);
    final Writer w = new BufferedWriter (new OutputStreamWriter (stm));
    final String lineSep = System.getProperty ("line.separator");
    w.write ("// This file was automatically generated by ");
    w.write (CategoriesGen.class.getName ());
    w.write (lineSep);
    if (pkg != null)
      w.write ("package " + pkg + ";" + lineSep + lineSep);
    w.write ("class " + className + " {" + lineSep);
    g.save (w, lineSep);
    w.write ("}" + lineSep);
    w.close ();
  }

  void load (final BufferedReader r) throws IOException
  {
    String lastCategory = null;
    int lastCode = 0;
    int firstCode = 0;
    for (;;)
    {
      final String line = r.readLine ();
      if (line == null)
        break;
      final int semi = line.indexOf (';');
      if (semi != 5 && semi != 6)
        continue;
      final int code = Integer.parseInt (line.substring (0, semi), 16);
      final int semi2 = line.indexOf (';', semi + 1);
      final String name = line.substring (semi, semi2);
      final String category = line.substring (semi2 + 1, semi2 + 3);
      if (!category.equals (lastCategory) || !(lastCode + 1 == code || name.endsWith (", Last>")))
      {
        if (lastCategory != null)
          add (firstCode, lastCode, lastCategory);
        lastCategory = category;
        firstCode = code;
      }
      lastCode = code;
    }
    if (lastCategory != null)
      add (firstCode, lastCode, lastCategory);
  }

  private final Map <String, List> map = new HashMap <String, List> ();

  static class Range
  {
    private final int lower;
    private final int upper;

    public Range (final int lower, final int upper)
    {
      this.lower = lower;
      this.upper = upper;
    }
  }

  void add (final int firstCode, final int lastCode, final String category)
  {
    List <Range> list = map.get (category);
    if (list == null)
    {
      list = new Vector <Range> ();
      map.put (category, list);
    }
    list.add (new Range (firstCode, lastCode));
  }

  static private final String INDENT = "  ";

  void save (final Writer w, final String lineSep) throws IOException
  {
    final Set set = map.entrySet ();
    w.write (lineSep);
    w.write (INDENT);
    w.write ("static final String CATEGORY_NAMES = \"");
    for (final Iterator iter = set.iterator (); iter.hasNext ();)
    {
      final Map.Entry entry = (Map.Entry) iter.next ();
      w.write ((String) entry.getKey ());
    }
    w.write ("\";");
    w.write (lineSep);
    w.write (lineSep);
    w.write (INDENT);
    w.write ("static final int[][] CATEGORY_RANGES = {");
    w.write (lineSep);

    for (final Iterator iter = set.iterator (); iter.hasNext ();)
    {
      final Map.Entry entry = (Map.Entry) iter.next ();
      w.write (INDENT);
      w.write (INDENT);
      w.write ('{');
      w.write (lineSep);
      w.write (INDENT);
      w.write (INDENT);
      w.write (INDENT);
      w.write ("// ");
      w.write ((String) entry.getKey ());
      w.write (lineSep);
      final List list = (List) entry.getValue ();
      for (int i = 0, len = list.size (); i < len; i++)
      {
        final Range r = (Range) list.get (i);
        w.write (INDENT);
        w.write (INDENT);
        w.write (INDENT);
        w.write ("0x");
        w.write (Integer.toHexString (r.lower));
        w.write (", ");
        w.write ("0x");
        w.write (Integer.toHexString (r.upper));
        if (i + 1 != len)
          w.write (",");
        w.write (lineSep);
      }
      w.write (INDENT);
      w.write (INDENT);
      w.write ('}');
      if (iter.hasNext ())
        w.write (',');
      w.write (lineSep);
    }
    w.write (INDENT);
    w.write ("};");
    w.write (lineSep);
  }
}
